﻿using DataAccessLayer;
using GlobalObjects;
using Microsoft.ApplicationServer.Caching;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using WCFServiceWebRole1.DataObjects;
using WCFServiceWebRole1.Pusher;

namespace WCFServiceWebRole1.Services
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "DataLogging" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select DataLogging.svc or DataLogging.svc.cs at the Solution Explorer and start debugging.

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
                 ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class DataLogging : IDataLogging
    {
        // string connectionString;
        static DataCache myCache;
        const string TopicName = "TemperatureDataLog";
        public const string SUBSCRIBED_SENSORS = "SubscribedSensors";
        public static SensorAccessTimeEntity monitorSensorEntity = new SensorAccessTimeEntity();
        public static DeviceEntity deviceEntity = new DeviceEntity();
        public static SubscriberList subscriberList = new SubscriberList();
        public static NotificationEntity notificationEntity = new NotificationEntity();
        #region Cache

        public List<int> SubscriberList
        {
            get
            {
                // Get Recent APIKeys from the cache
                myCache = WebRole.getCacheObject();
                var list = myCache.Get(SUBSCRIBED_SENSORS) as List<int>;
                if (list != null && list.Count == 0)
                {
                    List<int> newlist = allSubscribedSensors();
                    if (newlist != null)
                    {
                        if (newlist.Count == 0)
                        {
                            myCache.Put(SUBSCRIBED_SENSORS, 1277);
                           // list = myCache.Get(SUBSCRIBED_SENSORS) as List<int>;
                        }

                        foreach (var sub in newlist)
                        {
                            myCache.Put(SUBSCRIBED_SENSORS, sub);
                        }

                        list = myCache.Get(SUBSCRIBED_SENSORS) as List<int>;
                    }
                    else
                    {
                        myCache.Put(SUBSCRIBED_SENSORS, 1277);
                        list = myCache.Get(SUBSCRIBED_SENSORS) as List<int>;

                    }
                }
                return list;
            }
        }
        public void addSubcriber(int sensor)
        {
            //if (!SubscriberList.Contains(sensor))
            //{
            DataCache cache = WebRole.getCacheObject();
            cache.Put(SUBSCRIBED_SENSORS, sensor);
            //}
        }
        public List<int> allSubscribedSensors()
        {
            List<int> sensors = new List<int>();

            foreach (var sub in subscriberList.getSubscriberList())
            {
                //if (!sensors.Contains(sub.sensorid))
                //{
                sensors.Add(sub.sensorid);
                //}
            }
            return sensors;
        }

        #endregion

        #region Temperature Logging

        public string dataLogging(string sensorid, TempDataLog rawJson)
        {
            string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");

            //Stream rawj = rawJson.GetBody<Stream>();
            TopicClient Client = TopicClient.CreateFromConnectionString(connectionString, TopicName);
            
            #region creating json from stream
            //StreamReader reader = new StreamReader(rawJson);
            //string jsonstring = reader.ReadToEnd();

            //JavaScriptSerializer js = new JavaScriptSerializer();
            //dynamic item = js.Deserialize<object>(jsonstring);
            //object sensoridd = item["sensorId"];
            //object deviceid = item["DeviceId"];
            //            object firstime = item["firstTime"];
            //            object lastime = item["lastTime"];

            //object dataobj = item["data"];
            //string dataobjString="{\"data\":[";
            //List<object> list = ((IEnumerable)dataobj).Cast<object>().ToList();
            //string key;
            //object value;
            //foreach (Dictionary<string, object> dic in list)
            //{
            //    int count = 0;
            //    foreach (KeyValuePair<string, object> kv in dic)
            //    {
                    
            //        dataobjString += " {";   
            //        key = kv.Key;
            //        key = "\"" + key + "\"";
            //        string type = kv.Value.GetType().ToString();
            //        value = kv.Value;

            //        if (type != "System.String") { }
            //        else
            //        {
            //            value = "\"" + value + "\"";
            //        }
            //        if (count == 0)
            //        {
            //            dataobjString += key + ":" + value;

            //        }
            //        else { dataobjString += "," +key + ":" + value; }
            //        count++;
            //    }
            //    dataobjString += " },";              
            //}
            //dataobjString += "]}";
            #endregion
            //Get the ipaddress of the device from the http request
            OperationContext context = OperationContext.Current;
            MessageProperties messageProperties = context.IncomingMessageProperties;
            RemoteEndpointMessageProperty endpointProperty =
              messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
            string ipaddress = endpointProperty.Address.ToString();

            try
            {
               // Task.Factory.StartNew(() => updateAccessTime(rawJson.sensorId, rawJson.deviceId, ipaddress, DateTime.UtcNow));
                    updateAccessTime(rawJson.sensorId, rawJson.deviceId, ipaddress, DateTime.UtcNow);

                //deviceEntity.addIpAddress_DAL(rawJson.deviceId, ipaddress);
                //monitorSensorEntity.insertOrUpdateAcceessTime_DAL(rawJson.sensorId, DateTime.UtcNow.ToString());
                //monitorSensorEntity.setIp_DAL(rawJson.sensorId, ipaddress);
                // Create message, passing our model
                BrokeredMessage message = new BrokeredMessage(rawJson);
                message.Properties["MethodName"] = "dataLogging";

                message.Properties["UseCase"] = "One";

                //if (SubscriberList.Contains(rawJson.sensorId))
                //{
                //    message.Properties["PushAction"] = "Push";
                //}
                //else if (allSubscribedSensors().Contains(rawJson.sensorId))
                //{
                //    addSubcriber(rawJson.sensorId);
                //    message.Properties["PushAction"] = "Push";
                //}
                //else
                //{
                message.Properties["PushAction"] = "Push";
                //  }
                message.Properties["StoreAction"] = "Store";

                message.MessageId = sensorid;
                Client.Send(message);
                //CultureInfo ukCulture = new CultureInfo("en-GB");
                //DateTime myDate = DateTime.UtcNow;
                //String ukmyDate = myDate.ToString("dd/MM/yyyy HH:mm:ss", System.Globalization.CultureInfo.GetCultureInfo("en-us"));
                //DateTime now = DateTime.Parse(ukmyDate, ukCulture.DateTimeFormat);
                //monitorSensorEntity.insertOrUpdateAcceessTime_DAL(rawJson.sensorId, now.ToString());
            }
            catch (Exception ex)
            {
                ErrorData errordata = new ErrorData("Logging data failed." + ex.Message);
                errordata.StackTrace = ex.StackTrace;
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
            return "Success";
        }
        public string genericDataLogging(Stream rawJson)
        { 
            // convert stream to string
            StreamReader reader = new StreamReader(rawJson);
            string jsonstring = reader.ReadToEnd();

            JavaScriptSerializer js = new JavaScriptSerializer();
            dynamic item = js.Deserialize<object>(jsonstring);
            object sensorId = item["sensorId"];
            object deviceId = item["deviceId"];
            object firstTime = item["firstTime"];
            object lastTime = item["lastTime"];

            #region
            //object dataobj = item["data"];
            //string dataobjString = "{"+"\""+"data"+"\""+":[";
            //List<object> list = ((IEnumerable)dataobj).Cast<object>().ToList();
            //string key;
            //object value;
            //foreach (Dictionary<string, object> dic in list)
            //{
            //    int count = 0;
            //    dataobjString += "{";

            //    foreach (KeyValuePair<string, object> kv in dic)
            //    {

            //        key = kv.Key;
            //        key = "\"" + key + "\"";
            //        string type = kv.Value.GetType().ToString();
            //        value = kv.Value;

            //        if (type != "System.String") { }
            //        else
            //        {
            //            value = "\"" + value + "\"";
            //            //value = value ;

            //        }

            //        if (count == 0)
            //        {
            //            dataobjString += key + ":" + value;

            //        }
            //        else { dataobjString += "," + key + ":" + value; }
            //        count++;
            //    }
            //    dataobjString += " },";
            //}
            //dataobjString= dataobjString.Substring(0, dataobjString.Length - 1);
            //dataobjString += "]}";
            #endregion

            string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");

            //Stream rawj = rawJson.GetBody<Stream>();
            TopicClient Client = TopicClient.CreateFromConnectionString(connectionString, TopicName);

            //Get the ipaddress of the device from the http request
            OperationContext context = OperationContext.Current;
            MessageProperties messageProperties = context.IncomingMessageProperties;
            RemoteEndpointMessageProperty endpointProperty =
              messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
            string ipaddress = endpointProperty.Address.ToString();

            Task.Factory.StartNew(() => updateAccessTime(Convert.ToInt32(sensorId), Convert.ToInt32(deviceId), ipaddress, DateTime.UtcNow));
          //  updateAccessTime(Convert.ToInt32(sensorId), Convert.ToInt32(deviceId), ipaddress, DateTime.UtcNow);

            JavaScriptSerializer js2 = new JavaScriptSerializer();
            string text = js2.Serialize(item["data"]);
            String data = "{\"data\":" + text + "}";

            // Create message, passing our model
            BrokeredMessage message = new BrokeredMessage(data);
            message.Properties["PushAction"] = "Push";
            message.Properties["UseCase"] = "Two";
            message.Properties["StoreAction"] = "Store";
            message.Properties["deviceId"] = Convert.ToInt32(deviceId).ToString();
            message.Properties["sensorId"] = Convert.ToInt32(sensorId).ToString();

            message.MessageId = Convert.ToInt32(sensorId).ToString();
            Client.Send(message);

            return "Success";
        }
        public string notification(NotificationRequest notify)
        {
            OutgoingWebResponseContext outResponse = WebOperationContext.Current.OutgoingResponse;

            if (notify.reason == null || notify.reason == "")
            {
                ErrorData errordata = new ErrorData("Trigger Reason cannot be null.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }

            if (!deviceEntity.idExist_DAL(notify.deviceId))
            {
                ErrorData errordata = new ErrorData("Device Id does not exist.");
                throw new WebFaultException<ErrorData>(errordata, HttpStatusCode.BadRequest);
            }
           
            try
            {
                notificationEntity.insertNotification_DAL(notify.userId, notify.deviceId, notify.reason,notify.sensorId);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return "Success";
        }

        #endregion

   
     
        public static void LocalPing(IPAddress address)
        {
            // Ping's the local machine.
            Ping pingSender = new Ping();
         //   IPAddress address = IPAddress.Loopback;
            PingReply reply = pingSender.Send(address);

            if (reply.Status == IPStatus.Success)
            {
                Debug.WriteLine("Address: {0}", reply.Address.ToString());
                Debug.WriteLine("RoundTrip time: {0}", reply.RoundtripTime);
                Debug.WriteLine("Time to live: {0}", reply.Options.Ttl);
                Debug.WriteLine("Don't fragment: {0}", reply.Options.DontFragment);
                Debug.WriteLine("Buffer size: {0}", reply.Buffer.Length);
            }
            else
            {
                Console.WriteLine(reply.Status);
            }
        }

        private void updateAccessTime(int sensorId,int deviceid, string ipaddress, DateTime now)
        {
            monitorSensorEntity.insertOrUpdateAcceessTime_DAL(sensorId,now.ToString());
            deviceEntity.addIpAddress_DAL(deviceid, ipaddress);
            monitorSensorEntity.setIp_DAL(sensorId, ipaddress);
        }



        //private static T GetValue<T>(this JToken jToken, string key, T defaultValue = default(T))
        //{
        //    dynamic ret = jToken[key];
        //    if (ret == null) return defaultValue;
        //    if (ret is JObject) return JsonConvert.DeserializeObject<T>(ret.ToString());
        //    return (T)ret;
        //}




    }
}
